/*
 * newMockFile.h
 *
 *  Created on: Oct 28, 2012
 *      Author: Federico Orquera
 */

#ifndef NEWMOCKFILE_H_
#define NEWMOCKFILE_H_

#include <list>
#include <sstream>
#include <string>
#include <memory>
#include "MockDefinitions.h"

enum MockExceptions {
	NODE_NOT_FOUND
};

class newMockFile : public NewHandlerInterface< NodeID_t, NodeLevel_t, BPTkey_t, BPTvalue_t, keyComparator_func > {

public:

	newMockFile(const std::string& newFilename ){
		this->filename = newFilename;
		this->nodes.push_front(newLeaf());
		rootNodeID_t = (this->nodes.front())->getNodeID();
	}

	~newMockFile(){}

	node_ptr getNewRoot( const NodeLevel_t& level ){
		node_ptr oldRoot = getRoot();
		node_ptr newRoot = getNewNode(oldRoot->getLevel()+1);
		this->simpleInsert(newRoot);
		rootNodeID_t = newRoot->getNodeID();
		return newRoot;
	}

	node_ptr getRoot(){
		return this->getNode(rootNodeID_t);
	}

	node_ptr getNewNode(const NodeLevel_t& level){

		node_ptr newNode;

		if( level == LEAF_LEVEL )
			newNode = newLeaf();
		else
			newNode = newInternal( level );

		return newNode;

	}

	node_ptr getNode(const NodeID_t& id){

		this->simpleSearch( id );

		if(itNodes == (this->nodes).end())
			throw MockExceptions::NODE_NOT_FOUND;

		return   (*itNodes);

	}

	void saveNode( const node_ptr& node ){
		this->simpleInsert(node);
	}

	void deleteNode(const NodeID_t& id){
		this->simpleDelete(id);
	}

private:

	std::string 						filename;

	typedef std::shared_ptr < Node > 	node_ptr;
	typedef std::list< node_ptr >		node_list;
	node_list  							nodes;
	typename 	node_list::iterator  	itNodes;
	NodeID_t 							rootNodeID_t;

	NodeID_t GenerateID(){
	    static NodeID_t c_ID = 1;
	    return c_ID++;
	}

	void simpleSearch( const NodeID_t& key ){
		for ( itNodes=(this->nodes).begin() ; (itNodes != (this->nodes).end() && (*itNodes)->getNodeID() < key)  ; itNodes++ );
	}

	void simpleInsert( const node_ptr& registro ){
		simpleSearch( registro->getNodeID() );
		(this->nodes).insert (itNodes,registro);
	}

	void simpleDelete( const NodeID_t& key ){
		simpleSearch( key );
		if(itNodes == (this->nodes).end())throw MockExceptions::NODE_NOT_FOUND;
		(this->nodes).erase (itNodes);
	}

	node_ptr newLeaf(){

		node_ptr returnValue;

		returnValue.reset(
			new Leaf(
				ORDER,
				this->GenerateID(),
				&isOverflowLeaf_func,
				&isUnderflowLeaf_func
			)
		);

		return returnValue;

	}

	node_ptr newInternal(const NodeLevel_t& level){

		node_ptr returnValue;

		returnValue.reset(
			new Internal(
				ORDER,
				level,
				this->GenerateID(),
				&isOverflowInternal_func,
				&isUnderflowInternal_func,
				&cropKey_func,
				this
			)
		);

		return returnValue;

	}

};

#endif /* NEWMOCKFILE_H_ */
